package com.evil.account.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.evil.account.pojo.entity.User;
import com.evil.account.util.UserUtil;
import com.evil.common.account.dto.FindByNameAndEIdReqDTO;
import com.evil.common.account.dto.FindByNamesAndEIdReqDTO;
import com.evil.common.account.dto.user.UserBaseRespDTO;
import com.evil.common.account.dto.user.UserPageReqDTO;
import com.evil.common.account.dto.user.UserPageRespDTO;
import com.evil.common.account.util.AccountRedisKeyUtil;
import com.evil.common.core.constant.RedisConstant;
import com.evil.common.core.entity.QueryModel;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.CacheMapperUtil;
import com.evil.common.core.util.StreamUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.ibatis.annotations.Param;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 用户表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
public interface UserMapper extends BaseMapper<User> {

    default Optional<User> isExistById(Long id) {
        return Optional.ofNullable(this.selectById(id));
    }

    default Optional<User> isExistById_Cache(Long id) {
        return CacheMapperUtil.cacheById(
                id,
                User.class,
                this::findById,
                AccountRedisKeyUtil::requestUuidUserKey,
                RedisConstant.REQUEST_UUID_EXPIRE_IN_SECOND
        );
    }

    default User findById(Long id) {
        return this.isExistById(id).orElseThrow(() -> new BusinessException(RCodeEnum.USER_NOT_EXIST));
    }

    default User findById_Cache(Long id) {
        return this.isExistById(id).orElseThrow(() -> new BusinessException(RCodeEnum.USER_NOT_EXIST));
    }

    default User findNormalById(Long id) {
        return this.isExistById(id)
                .map(UserUtil::checkUser)
                .orElseThrow(() -> new BusinessException(RCodeEnum.USER_NOT_EXIST));
    }

    Optional<User> isExistByTel(@Param("tel") String tel);

    default User findByTel(String tel) {
        return this.isExistByTel(tel).orElseThrow(() -> new BusinessException(RCodeEnum.USER_NOT_EXIST));
    }

    Optional<User> isExistNormalByTel(@Param("tel") String tel);

    List<User> findByIds(@Param("ids") Collection<Long> ids, @Param("filterDeleted") boolean filterDeleted);

    List<User> findByTels(@Param("tels") Collection<String> tels, @Param("filterDeleted") boolean filterDeleted);

    default Map<Long, User> findMapByIds(Collection<Long> ids, boolean filterDeleted) {
        return StreamUtil.toMapK(this.findByIds(ids, filterDeleted), User::getUserId);
    }

    Optional<UserBaseRespDTO> isExistBaseById(@Param("id") Long id);

    default UserBaseRespDTO findBaseById(Long id) {
        return this.isExistBaseById(id).orElseThrow(() -> new BusinessException(RCodeEnum.USER_NOT_EXIST));
    }

    Optional<UserBaseRespDTO> isExistNormalBaseById(@Param("id") Long id);

    default UserBaseRespDTO findNormalBaseById(Long id) {
        return this.isExistNormalBaseById(id).orElseThrow(() -> new BusinessException(RCodeEnum.USER_NOT_EXIST));
    }

    Optional<UserBaseRespDTO> isExistBaseByName(FindByNameAndEIdReqDTO findByNameAndEIdReqDTO);

    default UserBaseRespDTO findBaseByName(FindByNameAndEIdReqDTO findByNameAndEIdReqDTO) {
        return this.isExistBaseByName(findByNameAndEIdReqDTO).orElseThrow(() -> new BusinessException(RCodeEnum.USER_NOT_EXIST));
    }

    List<UserBaseRespDTO> findBaseByIds(@Param("ids") Collection<Long> ids, @Param("filterDeleted") boolean filterDeleted);

    List<UserBaseRespDTO> findBaseByNames(FindByNamesAndEIdReqDTO findByNamesAndEIdReqDTO);

    default List<UserBaseRespDTO> findBaseByIds_Cache(Collection<Long> ids, boolean filterDeleted) {
        return CacheMapperUtil.cacheByIds(
                ids,
                filterDeleted,
                UserBaseRespDTO.class,
                this::findBaseByIds,
                UserBaseRespDTO::getUserId,
                u -> SwitchEnum.NO.getId(),
                null,
                AccountRedisKeyUtil::requestUuidUserBaseKeyMap,
                RedisConstant.REQUEST_UUID_EXPIRE_IN_SECOND
        );
    }

    default Map<Long, UserBaseRespDTO> findBaseMapByIds(Collection<Long> ids, boolean filterDeleted) {
        return StreamUtil.toMapK(this.findBaseByIds(ids, filterDeleted), UserBaseRespDTO::getUserId);
    }

    List<UserPageRespDTO> userList(UserPageReqDTO userPageReqDTO);

    default PageInfo<UserPageRespDTO> userPage(QueryModel<UserPageReqDTO> queryModel) {
        return PageHelper.startPage(queryModel.getPageNum(), queryModel.getPageSize(), queryModel.initOrder())
                .doSelectPageInfo(() -> this.userList(queryModel.getParam()));
    }

    List<UserBaseRespDTO> userBases(UserPageReqDTO userPageReqDTO);

    default PageInfo<UserBaseRespDTO> userBasePage(QueryModel<UserPageReqDTO> queryModel) {
        return PageHelper.startPage(queryModel.getPageNum(), queryModel.getPageSize(), queryModel.initOrder())
                .doSelectPageInfo(() -> this.userBases(queryModel.getParam()));
    }

    /**
     * 查询某企业下的用户数量，不包括已删除用户
     *
     * @param enterpriseId enterpriseId
     * @param isEnable     禁用状态-null忽略条件
     * @param unallocated  部门分配状态-null忽略条件
     * @return Integer
     */
    Integer findUserCount(@Param("enterpriseId") Long enterpriseId,
                          @Param("isEnable") Integer isEnable,
                          @Param("unallocated") Boolean unallocated);
}